#include <OpenNetwork/OpenNetwork.h>

#include <iostream>

//! Use our namespace
using namespace onet;
using namespace std;

//! Settings
const u16 numConnections = 1000;
const EPortType port = EPT_UserDatagramProtocol;

//! Value used while waiting for sucessful connection
bool connected = false;
PeerID id = -1;

class Callback : public INetworkCallback
{
public:
    virtual void onPeerConnect(const PeerID id_)
    {
        if (!connected)
        {
            cout << "Another one! (" << id_+1 << ")" << endl;

            id = id_;
            connected = true;
        }
    }

    virtual void onPeerDisconnect(const PeerID id_, const ENetworkInformation info)
    {
        if (info == ENI_ConnectionClosed)
            cout << "Sucessfully disconnected" << endl;
        else if (info == ENI_ConnectionTimeout)
            cout << "Connection timed out" << endl;

        connected = false;
        id = -1;
    }
};

//! The main function
int main()
{
    Callback callback;

    cout << "Initializing...";

    //! Call this before starting any network stuff
    start();

    INetworkPort* receiver = createNetworkPort(port, &callback, numConnections, 50000, true, false);
    INetworkPort* sender[numConnections];

    for (u16 u = 0; u < numConnections; u++)
        sender[u] = 0;

    if (!receiver->init())
    {
        cout << "Error!" << endl;

        delete receiver;

        end();

        return -1;
    }

    cout << "Done!" << endl;

    f32 start = getLocalTime();

    for (u16 u = 0; u < numConnections; u++)
    {
        connected = false;

        sender[u] = createNetworkPort(port, &callback, 1, 0, false, false);

        if (sender[u]->init())
        {
            sender[u]->connect(createAddressFromURL("projectfreedom.no-ip.biz", 50000));

            cout << u+1 << "...";

            while (!connected)
            {
                sender[u]->work();
                receiver->work();
            }

            sender[u]->disconnect(id);

            while (connected)
            {
                sender[u]->work();
                receiver->work();
            }
        }
        else
        {
            delete sender[u];
            sender[u] = 0;

            cout << "Couldn't setup sender!" << endl;
        }
    }

    //! Print out some informations
    cout << numConnections << " Peers took " << (getLocalTime() - start)/1000.0f << " seconds to connect." << endl;
    cout << "This means " << numConnections * 1000 / (getLocalTime()-start) << " peers per second." << endl;

    //! Clean up
    delete receiver;

    for (u16 u = 0; u < numConnections; u++)
    {
        if (sender[u])
            delete sender[u];
    }

    end();

    return 1;
}
